//@ts-nocheck
import {REACT_ELEMENT_TYPE} from '../shared/ReactSymbols';

const SEPARATOR = '.'; //表示开头的
const SUB_SEPARATOR = ':'; //表示层级的
/**
 *
 * @param children 要映射的元素, 可能是一个数组, 也可能是一个可渲染的节点
 * @param mapFunction
 * @param context
 *
 * 最终我们会把映射出来的所有节点都放在result里面
 */
function mapChildren(children, mapFunction , context){
  const result = [];
  mapIntoWithKeyPrefixInternal(children, result, null, mapFunction, context);
  return result;
}

function mapIntoWithKeyPrefixInternal(children, result, prefix /** ←如果不是null, 则是由下面mapSingleChildIntoContext调用的 第一次时,本例中为 .0:0*/, mapFunction, context) {
  // + prefix 指的是渲染前的索引 .0:0/.0 中的.0:0/
  if (prefix != null) {
    prefix = prefix + '/'; // .0:0 => .0:0/
  }

  //traverseContext 遍历的上下文, 即遍历时会用到的上下文
  const traverseContext = {result, prefix, mapFunction, context};
  traverseAllChildren(children, '', mapSingleChildIntoContext, traverseContext);
}

function traverseAllChildren(children, nameSoFar/** ←意思是 "到现在为止的名字" */, mapSingleChildIntoContext, traverseContext){
  const type = typeof children;
  // 如果type是字符串或者数字, 或则type是一个对象, 但是children.$$typeof是一个React元素
  if(type === 'string' || type === 'number' || (type === 'object' && children.$$typeof === REACT_ELEMENT_TYPE)){
    mapSingleChildIntoContext(traverseContext, children, nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar);
  }else if (Array.isArray(children)){ // [Array(2), Array(2)]
    const nextNamePrefix = nameSoFar === '' ? SEPARATOR/** ← .*/ : nameSoFar + SUB_SEPARATOR /** ← nameSoFar:*/;
    for (let i = 0; i < children.length; ++i) {
      const child = children[i]; // Array(2) ->  [<span>A</span>,<span key="keyB">B</span>] // <span>A</span>
      const nextName = nextNamePrefix + getComponentKey(child, i); // .0 // .0:0
      traverseAllChildren(child, nextName, mapSingleChildIntoContext, traverseContext);
    }
  }
}

function getComponentKey(component, index) {
  return component.key || index.toString(36); // 如果此节点有自己的key就用自己的,如果没有就用索引
}

function mapSingleChildIntoContext(traverseContext, child/** ←<span>A</span>*/, childKey /** ←.0:0*/) {
  const {result, prefix, mapFunction, context} = traverseContext;
  const mappedChild = mapFunction.call(context, child);
  if (Array.isArray(mappedChild)) {
    // 如果映射出的是一个数组, 要展开
    mapIntoWithKeyPrefixInternal(mappedChild, result, childKey /** ←.0:0*/, c => c, context);
  }else{
    result.push({...mappedChild, key: prefix + childKey}); // .0:0/
  }
}

export {
  mapChildren as map
}


/** emmmm 上面是react源码的写法 其实可以更简单的实现 像下面这样↓*/
function mapChildren2(children, mapFunction, context){
  return children.flat(Infinity).map(mapFunction).flat(Infinity)
}
